﻿//Copyright (c) 2010 Christopher E. S. King (http://chriskingconsulting.com)
//
//Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files 
// (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, 
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do 
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using System.Reflection;
using System.Collections;
using System.IO;
using System.Diagnostics.Contracts;

using King.Extensions;
using King.Text;
using King.Reflection;
using King.Language;

using Antlr.Runtime;
using Antlr.Runtime.Tree;
using King.Antlr3;

namespace King.Language.CSharp {

    internal partial class AntlrCSharpParser {

        partial void OnCreated() {
        }

        protected override object RecoverFromMismatchedToken(IIntStream input, int ttype, BitSet follow) {
            throw new MismatchedTokenException(ttype, input, TokenNames);
        }
        public override void Recover(IIntStream input, RecognitionException re) {
            throw re;
        }

        private AntlrCSharpLexer Lexer { 
            get { return (AntlrCSharpLexer)TokenStream.TokenSource; } 
        }

        private int m_indent;
        partial void EnterRule(string ruleName, int ruleIndex) {
            Console.WriteLine("".PadLeft(m_indent++) + "Enter " + ruleName + " " + ruleIndex);
        }
        partial void LeaveRule(string ruleName, int ruleIndex) {
            Console.WriteLine("".PadLeft(--m_indent) + "Leave " + ruleName + " " + ruleIndex);
        }

        public int InTypeArgumentList {
            get { return Lexer.InTypeArgumentList; }
            set { Lexer.InTypeArgumentList = value; }
        }
    }
    internal partial class AntlrCSharpLexer {

        private int m_inTypeArgumentList;
        private TokenTreeAdaptor m_tokenTreeAdapter;
        private IEnumerable<string> m_preProcessorSymbols;
        private AntlrCSharpPreProcessorParser m_preProcessor;

        partial void OnCreated() {
        }

        public override void Recover(IIntStream input, RecognitionException re) {
            throw re;
        }
        public override void Recover(RecognitionException re) {
            throw re;
        }
        protected override object RecoverFromMismatchedToken(IIntStream input, int ttype, BitSet follow) {
            throw new MismatchedTokenException(ttype, input, TokenNames);
        }

        protected override void ParseNextToken() {
            if (input.LA(1) == CharStreamConstants.EndOfFile)
                Emit(m_tokenTreeAdapter.Create(TokenTypes.EndOfFile, null, state.channel, 0, 0, 0, 0));

            else
                mTokens();
        }

        public override NillableToken Emit() {
            var token = m_tokenTreeAdapter.Create(
                state.type, state.text, state.channel, state.tokenStartCharIndex, 
                CharIndex - state.tokenStartCharIndex,
                state.tokenStartLine, state.tokenStartCharPositionInLine);

            Emit(token);

            if (!state.skip) {
                Console.WriteLine(state.text + " " + token.ToString());
            }
            return token;
        }
        public int InTypeArgumentList {
            get { return m_inTypeArgumentList; }
            set { m_inTypeArgumentList = value; }
        }

        public TokenTreeAdaptor TokenTreeAdapter {
            get { return m_tokenTreeAdapter; }
            set { m_tokenTreeAdapter = value; }
        }

        internal void AddPreProcessorSymbols(IEnumerable<string> preProcessorSymbols) {
            m_preProcessorSymbols = preProcessorSymbols;
        }

        internal void PreProcess() {

            if (m_preProcessor == null) {
                var adapter = new TokenTreeAdaptor(
                    m_tokenTreeAdapter.Allocator,
                    tokenNames: AntlrCSharpPreProcessorParser.tokenNames,
                    stream: m_tokenTreeAdapter.Stream);

                // activate pre-processor parser
                var lexer = new AntlrCSharpPreProcessorLexer(input);
                var tokens = new MyCommonTokenStream(lexer);
                var parser = new AntlrCSharpPreProcessorParser(tokens);

                // expose adapter to create tokens/trees
                parser.TreeAdaptor = adapter;
                lexer.TokenTreeAdapter = adapter;

                // set symbols
                parser.AddPreProcessorSymbols(m_preProcessorSymbols);

                m_preProcessor = parser;
            }

            // pre-process code
            var rule = "start";
            var scope = (IAstRuleReturnScope)typeof(AntlrCSharpPreProcessorParser).Invoke(rule, m_preProcessor);

            //var nillableToken = (NillableToken)scope.Tree;
            //var antlrToken = nillableToken.AntlrToken;
            //var token = new CSharpPreProcessorToken(adapter, antlrToken);

            //return token;
        }
    }
}
